import { useRef } from 'react';
import { useSyncState } from './useSyncState';
/** 对象操作方法库 */
import _ from 'lodash';
export const useReactive = (params) => {
    /** 缓存state，解决设置setState时因为闭包导致state不是最新值 */
    const cacheReactiveState = useRef(params);
    /** 根据对象属性路径，生成Proxy代理对象的handle */
    const getProxyHandle = (path) => {
        return {
            set(target, key, value) {
                Object.assign(target, { [key]: value });
                /** 获取缓存state并修改属性值 */
                const cloneState = _.set({ ...cacheReactiveState.current }, [...path, key], value);
                /** 因为cloneState已经被拓展运算符结构了，需要重新构建响应式Proxy对象 */
                const _state = createReactiveObject(cloneState);
                setState(_state, () => {
                    /** 更新缓存state */
                    cacheReactiveState.current = _state;
                });
                return true;
            },
            get(target, key) {
                if (typeof target[key] === 'function') {
                    /** 克隆缓存state原理同上注释 */
                    return (...args) => {
                        const result = target[key]?.(...args);
                        const cloneState = _.set({ ...cacheReactiveState.current }, [...path], target);
                        const res = createReactiveObject(cloneState);
                        setState(res, () => {
                            cacheReactiveState.current = res;
                        });
                        return result;
                    };
                }
                return target[key];
            }
        };
    };
    /** 根据对象路径递归生成Proxy代理对象，实现对象每一层都是个Proxy响应式对象 */
    const createReactiveObject = (_params, path = []) => {
        // 不是对象直接导出
        if (typeof _params !== 'object')
            return _params;
        // 遍历对象深层属性，对于引用型属性递归生成proxy对象
        Object.keys(_params).forEach((key) => {
            if (typeof _params[key] === 'object') {
                const targetReactive = _params[key] instanceof Array ? [..._params[key]] : { ..._params[key] };
                Object.assign(_params, {
                    [key]: createReactiveObject(targetReactive, [...path, key])
                });
            }
        });
        const resReactive = _params instanceof Array ? [..._params] : { ..._params };
        return new Proxy(resReactive, getProxyHandle([...path]));
    };
    const reactiveObject = createReactiveObject(params);
    cacheReactiveState.current = reactiveObject;
    const [state, setState] = useSyncState(reactiveObject);
    return state;
};
